
using System;
using System.Collections.Generic; 
using System.IO; 
using System.Text;
using System.Threading.Tasks; 
using UnityEngine;

namespace XFGameFramework
{
  
    public class LogUtil
    {

        #region 静态字段

        private static StringBuilder TempStringBuilder = new StringBuilder();
        private static Queue<string> WaitToWriteFileLogs = new Queue<string>();
        private static bool WritingFile = false;
        private static Task WriteToFileTask = null;
        private static bool isStopWriteToFile = false;
        private static StreamWriter writer = null;
        #endregion

        #region 静态属性

        /// <summary>
        /// 日志文件所在的目录
        /// </summary>
        public static string LogFileDirectory => string.Format("{0}/Logs", Application.temporaryCachePath);

        /// <summary>
        /// 当前进程写入的日志文件路径
        /// </summary>
        public static string LogFilePath
        {
            get; private set;
        }

        #endregion

        #region 静态事件

        /// <summary>
        /// 当有异常时触发(Debug.unityLogger.logEnabled需为打开状态，否则该事件不会触发)
        /// </summary>
        public static System.Action OnException;
        #endregion

        #region 静态方法

        [RuntimeInitializeOnLoadMethod]
        static void InitLogUtil()
        {
            WaitToWriteFileLogs.Clear();
            WritingFile = false;
            WriteToFileTask = null;
            isStopWriteToFile = false;
            writer = null;

            Application.logMessageReceived -= OnReceiveLog;
            Application.logMessageReceived += OnReceiveLog;
            CheckLogFileDate();

            LogFilePath = string.Empty;

#if !LOG_UTIL_WRITE_TO_FILE_DISABLE
            LogFilePath = string.Format("{0}/player_log_{1}.txt", LogFileDirectory, DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss"));
#endif
        }

        public static void Log(string message, params object[] args)
        {

#if !LOG_UTIL_WRITE_TO_CONSOLE_DISABLE
            if (args == null || args.Length == 0)
                Debug.Log(message);
            else
                Debug.LogFormat(message, args);
#endif

#if !LOG_UTIL_WRITE_TO_FILE_DISABLE
            if (isStopWriteToFile) return;
            TempStringBuilder.Clear();
            TempStringBuilder.Append("[").Append(DateTime.Now.ToString()).Append("]").Append("[Log]").Append(string.Format(message,args)).AppendLine();
            ReadyWriteToFile(TempStringBuilder.ToString());
#endif

        }

        public static void LogWarning(string message, params object[] args)
        {

#if !LOG_UTIL_WRITE_TO_CONSOLE_DISABLE
            if (args == null || args.Length == 0)
                Debug.LogWarning(message);
            else
                Debug.LogWarningFormat(message, args);
#endif

#if !LOG_UTIL_WRITE_TO_FILE_DISABLE
            if (isStopWriteToFile) return;
            TempStringBuilder.Clear();
            TempStringBuilder.Append("[").Append(DateTime.Now.ToString()).Append("]").Append("[Warning]").Append(string.Format(message, args)).AppendLine();
            ReadyWriteToFile(TempStringBuilder.ToString());
#endif
        }

        public static void LogError(string message, params object[] args)
        {

#if !LOG_UTIL_WRITE_TO_CONSOLE_DISABLE
            if (args == null || args.Length == 0)
                Debug.LogError(message);
            else
                Debug.LogErrorFormat(message, args);
#endif

#if !LOG_UTIL_WRITE_TO_FILE_DISABLE
            if (isStopWriteToFile) return;
            TempStringBuilder.Clear();
            TempStringBuilder.Append("[").Append(DateTime.Now.ToString()).Append("]").Append("[Error]").Append(string.Format(message, args)).AppendLine();
            ReadyWriteToFile(TempStringBuilder.ToString());
#endif

        }

        public static void StopWriteToFile()
        {
            try
            {
                isStopWriteToFile = true;
                WaitToWriteFileLogs.Clear();
                if (writer != null)
                {
                    writer.Close();
                    writer = null;
                }
            }
            catch (Exception)
            {
            }

        }


        /// <summary>
        /// 检测日志文件是否超过三天，如果超过三天就清理掉
        /// </summary>
        private static void CheckLogFileDate()
        {
            if (!Directory.Exists(LogFileDirectory)) return;

            // 异步检测 防止影响游戏启动时间 
            Task.Run(() =>
            {
                string[] files = Directory.GetFiles(LogFileDirectory);
                for (int i = 0; i < files.Length; i++)
                {
                    try
                    {
                        DateTime createTime = File.GetCreationTime(files[i]);
                        if ((DateTime.Now - createTime).Days > 3)
                        {
                            File.Delete(files[i]);
                        }
                    }
                    catch (Exception)
                    {
                    }
                }
            });
        }

        private static void OnReceiveLog(string condition, string stackTrace, LogType type)
        {
            // 这里只关心报错信息
            if (type != LogType.Exception) return;

#if !LOG_UTIL_WRITE_TO_FILE_DISABLE
            if (isStopWriteToFile) return;
            TempStringBuilder.Clear();
            TempStringBuilder.Append("[").Append(DateTime.Now.ToString()).Append("]").Append("[").Append(type.ToString()).Append("]").Append(condition).AppendLine();
            TempStringBuilder.AppendLine(stackTrace);
            ReadyWriteToFile(TempStringBuilder.ToString());
#endif

#if !UNITY_EDITOR
            OnException?.Invoke(); // 如果抛异常并且非Editor模式，触发事件
#endif

        }

        private static void StartWriteToFile()
        {
            if (WritingFile) return;
            WritingFile = true;
            // 需要监听编辑器状态 关掉任务 TODO
            WriteToFileTask = Task.Run(() =>
            { 
                try
                {
                    string dir = Path.GetDirectoryName(LogFilePath);
                    if (!Directory.Exists(dir))
                        Directory.CreateDirectory(dir);

                    writer = File.AppendText(LogFilePath);
                    while (WaitToWriteFileLogs.Count > 0)
                    {
                        writer.WriteLine(WaitToWriteFileLogs.Dequeue());
                        writer.Flush();
                    }
                    writer.Close();
                }
                catch (Exception)
                {
                }

                writer = null;
                WritingFile = false;
                WriteToFileTask = null;
            });
        }

        private static void ReadyWriteToFile(string message)
        {
            if (isStopWriteToFile) return;
#if !LOG_UTIL_WRITE_TO_FILE_DISABLE

            try
            {
                // 写入文件
                WaitToWriteFileLogs.Enqueue(message);
                // 开始写入
                StartWriteToFile();
            }
            catch (Exception)
            {
            }
#endif 
        }
        #endregion


    } 
}


